#include "cGamma.h"

// CONSTRUCTOR
cGamma::cGamma() {
}

// DESTRUCTIR
cGamma::~cGamma() {
}

// devuelve una lista de bytes con la codificación en gamma de un numero
tListaBytes* cGamma::codificacion(int numero)
{
	bool vecPos[32];
	unsigned int cantUnario, logX, nroBinario, cantBits, j, aux;
	tListaBytes* res = new tListaBytes();

	for(j = 0; j < 32; j++)
	{
	vecPos[j] = 0;
	}

	logX = (unsigned int)((log(numero)/log(2))+0.00000000001);
	cantUnario = 1 + logX;
	nroBinario = (unsigned int)((numero) - (pow(2,logX)));
	cantBits = cantUnario + logX;

	if(cantBits <= 8)
	{
		unsigned char codigo = 0;

		for(j=0; j<cantUnario-1; j++)
		{
			aux = (unsigned int)(pow(2,(7-j)));
			(codigo|=aux);
		}

		ObtenerBitsPrendidos(vecPos,nroBinario);

		for(j=0; j<logX; j++)
		{
			if(vecPos[31-j] == 1)
			{
				aux = (unsigned int)(pow(2,(8-cantBits+j)));
				(codigo|=aux);
			}
		}
		res->push_back(codigo);
	}
	else
	if((cantBits>8)&&(cantBits<=16))
	{
		unsigned char codigo1 = 0;
		unsigned char codigo2 = 0;

		for(j=0; j<cantUnario-1; j++)
		{
			if(j<8)
			{
				aux = (unsigned int)(pow(2,(7-j)));
				(codigo1|=aux);
			}
			else
			{
				aux = (unsigned int)(pow(2,(15-j)));
				(codigo2|=aux);
			}
		}

		ObtenerBitsPrendidos(vecPos,nroBinario);

		for(j=0; j<logX; j++)
		{
			if(vecPos[31-j] == 1)
			{
				if((16-cantBits+j)<8)
				{
					aux = (unsigned int)(pow(2,(16-cantBits+j)));
					(codigo2|=aux);
				}
				else
				{
					aux = (unsigned int)(pow(2,(8-cantBits+j)));
					(codigo1|=aux);
				}
			}
		}

		res->push_back(codigo1);
		res->push_back(codigo2);
	}
	else
	if((cantBits>16)&&(cantBits<=24))
	{
		unsigned char codigo1 = 0;
		unsigned char codigo2 = 0;
		unsigned char codigo3 = 0;

		for(j=0; j<cantUnario-1; j++)
		{
			if(j<8)
			{
				aux = (unsigned int)(pow(2,(7-j)));
				(codigo1|=aux);
			}
			else
			if((j>=8) && (j<16))
			{
				aux = (unsigned int)(pow(2,(15-j)));
				(codigo2|=aux);
			}
			else
			{
				aux = (unsigned int)(pow(2,(23-j)));
				(codigo3|=aux);
			}
		}

		ObtenerBitsPrendidos(vecPos,nroBinario);

		for(j=0; j<logX; j++)
		{
			if(vecPos[31-j] == 1)
			{
				if((24-cantBits+j)<8)
				{
					aux = (unsigned int)(pow(2,(24-cantBits+j)));
					(codigo3|=aux);
				}
				else
				if(((24-cantBits+j)>=8) && ((24-cantBits+j)<16))
				{
					aux = (unsigned int)(pow(2,(16-cantBits+j)));
					(codigo2|=aux);
				}
				else
				{
					aux = (unsigned int)(pow(2,(8-cantBits+j)));
					(codigo1|=aux);
				}
			}
		}

		res->push_back(codigo1);
		res->push_back(codigo2);
		res->push_back(codigo3);
	}
	else
	if((cantBits>24)&&(cantBits<=32))
	{
		unsigned char codigo1 = 0;
		unsigned char codigo2 = 0;
		unsigned char codigo3 = 0;
		unsigned char codigo4 = 0;

		for(j=0; j<cantUnario-1; j++)
		{
			if(j<8)
			{
				aux = (unsigned int)(pow(2,(7-j)));
				(codigo1|=aux);
			}
			else
			if((j>=8) && (j<16))
			{
				aux = (unsigned int)(pow(2,(15-j)));
				(codigo2|=aux);
			}
			else
			if((j>=16) && (j<24))
			{
				aux = (unsigned int)(pow(2,(23-j)));
				(codigo3|=aux);
			}
			else
			{
				aux = (unsigned int)(pow(2,(31-j)));
				(codigo4|=aux);
			}
		}

		ObtenerBitsPrendidos(vecPos,nroBinario);

		for(j=0; j<logX; j++)
		{
			if(vecPos[31-j] == 1)
			{
				if((32-cantBits+j)<8)
				{
					aux = (unsigned int)(pow(2,(32-cantBits+j)));
					(codigo4|=aux);
				}
				else
				if(((32-cantBits+j)>=8) && ((32-cantBits+j)<16))
				{
					aux = (unsigned int)(pow(2,(24-cantBits+j)));
					(codigo3|=aux);
				}
				else
				if(((32-cantBits+j)>=16) && ((32-cantBits+j)<24))
				{
					aux = (unsigned int)(pow(2,(16-cantBits+j)));
					(codigo2|=aux);
				}
				else
				{
					aux = (unsigned int)(pow(2,(8-cantBits+j)));
					(codigo1|=aux);
				}
			}
		}

		res->push_back(codigo1);
		res->push_back(codigo2);
		res->push_back(codigo3);
		res->push_back(codigo4);
	}
	else
	{
		unsigned char codigo1 = 0;
		unsigned char codigo2 = 0;
		unsigned char codigo3 = 0;
		unsigned char codigo4 = 0;
		unsigned char codigo5 = 0;

		for(j=0; j<cantUnario-1; j++)
		{
			if(j<8)
			{
				aux = (unsigned int)(pow(2,(7-j)));
				(codigo1|=aux);
			}
			else
			if((j>=8) && (j<16))
			{
				aux = (unsigned int)(pow(2,(15-j)));
				(codigo2|=aux);
			}
			else
			if((j>=16) && (j<24))
			{
				aux = (unsigned int)(pow(2,(23-j)));
				(codigo3|=aux);
			}
			else
			if((j>=24) && (j<32))
			{
				aux = (unsigned int)(pow(2,(31-j)));
				(codigo4|=aux);
			}
			else
			{
				aux = (unsigned int)(pow(2,(39-j)));
				(codigo5|=aux);
			}
		}

		ObtenerBitsPrendidos(vecPos,nroBinario);

		for(j=0; j<logX; j++)
		{
			if(vecPos[31-j] == 1)
			{
				if((40-cantBits+j)<8)
				{
					aux = (unsigned int)(pow(2,(40-cantBits+j)));
					(codigo5|=aux);
				}
				else
				if(((40-cantBits+j)>=8) && ((40-cantBits+j)<16))
				{
					aux = (unsigned int)(pow(2,(32-cantBits+j)));
					(codigo4|=aux);
				}
				else
				if(((40-cantBits+j)>=16) && ((40-cantBits+j)<24))
				{
					aux = (unsigned int)(pow(2,(24-cantBits+j)));
					(codigo3|=aux);
				}
				else
				if(((40-cantBits+j)>=24) && ((40-cantBits+j)<32))
				{
					aux = (unsigned int)(pow(2,(16-cantBits+j)));
					(codigo2|=aux);
				}
				else
				{
					aux = (unsigned int)(pow(2,(8-cantBits+j)));
					(codigo1|=aux);
				}
			}
		}

		res->push_back(codigo1);
		res->push_back(codigo2);
		res->push_back(codigo3);
		res->push_back(codigo4);
		res->push_back(codigo5);
	}

	return res;
}

// devuelve el numero que corresponde a una lista de bytes en gamma
int cGamma::decodificacion(tListaBytes & codificacion)
{
	bool continuar;
	int c;
	int i;
	unsigned char byte,mod,cantBits;
	unsigned int b;
	unsigned int aux;
	unsigned int mascara;
	int numeroDecodificado;

	continuar = true;
	c = 0;
	b = 0;
	mascara = 0;
	numeroDecodificado = 0;
	cantBits = 0;

	while(continuar)
	{
		byte = codificacion.front();
		codificacion.pop_front();
		for(i = 0; i < 8; i++)
		{
			mascara = (unsigned int)(pow(2,(7-i)));
			if(byte & mascara)
				c++;
			else
			{
				continuar = false;
				break;
			}
		}
	}

	c++;
	mod = c%8;
	
	if(mod == 0)
	{
		cantBits = c-1;
	}
	else
	{
		for(i=0;i<(8-mod);i++)
		{
			mascara = (unsigned int)(pow(2,(7-mod-i)));
			if(byte & mascara)
			{
				mascara = (unsigned int)(pow(2,(c-2-i)));
				(b|=mascara);
			}
		}
		cantBits = c - 1 - (8-mod);
	}

	while((cantBits>0)&&(cantBits<40))
	{
		byte = codificacion.front();
		codificacion.pop_front();
		for(i = 0; i < 8; i++)
		{
			mascara = (unsigned int)(pow(2,(7-i)));
			if(byte & mascara)
			{
				mascara = (unsigned int)(pow(2,(cantBits-1)));
				(b|=mascara);
			}
			cantBits--;
		}
	}

	aux = (unsigned int)(pow(2,(c-1)));
	numeroDecodificado = aux + b;

	return numeroDecodificado;
}

void cGamma::ObtenerBitsPrendidos(bool vecPos[],unsigned int nroBinario)
{
	unsigned int i, res, aux;

	for(i=0; i<32; i++)
	{
		aux = (unsigned int)(pow(2,31-i));
		res = (nroBinario & aux);
		if(res == aux)
		{
			vecPos[i] = 1;
		}
	}
}
